import { EventsRes, ICircleParams } from '@amcax/base';
import { ctx2 } from '@app-cad/module';
import { addDimension, axis, isParallel } from '@app-cad/common/utils';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '@app-cad/environments/nextcad/events/SketchEventCenter';
import { Vector2tuple, Vector3 } from 'three-legacy';
import CmdBase from '../../CmdBase';
import { dimRender } from '../cmd-render-pick/render';
import { DimLinear } from '../dimension/DimLinear';
import { AnnotationType } from '../dimension/types';
import { MouseState, State } from './types';

export default class CmdInteractor extends CmdBase {
  drawState: MouseState = State.NONE;
  curveIds: string[] = [];
  labelPosLV: Vector3 = new Vector3();
  dimLinear: DimLinear;
  endPoint: Vector3 = new Vector3();
  isExist: boolean = false;
  vertices: Vector2tuple[][];
  lineVecs: Vector3[] = [];
  parallel: boolean = true;

  constructor() {
    super();
    this.registerEvents();
    this.picker.clickNull();
  }

  reset() {
    this.drawState = State.NONE;
    this.pickSnapInfo = null;
    this.lineVecs = [];
  }

  unregisterEvents() {
    sketchEventCenter()
      .off(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .off(SKETCH_CENTEREVENTS.POINTERUP, this.onMouseUp)
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .setDefault();
  }

  registerEvents() {
    sketchEventCenter()
      .setState('dimlinear')
      .on(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .on(SKETCH_CENTEREVENTS.POINTERUP, this.onMouseUp)
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy.bind(this));
  }

  onMouseDown = ({ button }: EventsRes) => {
    if (button.onLeft && this.pickSnapInfo) {
      this.dimLinear?.unClickFocus();
    }
  };
  onMouseUp = ({ button }: EventsRes) => {
    if (button.onLeft) {
      if (this.drawState < State.DRAWTWO) {
        if (
          this.pickSnapInfo?.type === 'Line' ||
          this.pickSnapInfo?.type === 'Point' ||
          this.hasCenter()
        ) {
          let vertice = this.pickSnapInfo.vertices;
          if (this.hasCenter()) {
            const param = this.pickSnapInfo?.params as ICircleParams;
            vertice = [param.center];
          }
          if (this.pickSnapInfo.type === 'Line') {
            this.lineVecs.push(
              new Vector3(
                vertice[1][0] - vertice[0][0],
                vertice[1][1] - vertice[0][1],
                0,
              ),
            );
          }
          if (this.drawState === State.DRAWONE && this.lineVecs.length === 2) {
            this.parallel = isParallel(
              this.lineVecs[0].normalize(),
              this.lineVecs[1].normalize(),
            );
          }
          const id = this.hasCenter()
            ? this.pickSnapInfo.relative[0]
            : this.pickSnapInfo.id;
          if (this.parallel && !this.curveIds.includes(id)) {
            this.curveIds.push(id);
            if (this.drawState === State.NONE) {
              this.vertices = [vertice];
            } else {
              this.vertices.push(vertice);
            }
            if (
              this.curveIds.length !== 1 ||
              !axis.includes(this.curveIds[0])
            ) {
              this.addLine();
            }
            this.drawState = this.drawState + 1;
          } else {
            this.parallel = true;
            this.lineVecs.pop();
          }
          this.dimLinear?.labelFoucs();
        }
      }
    } else if (button.onRight && !this.closeRightClick) {
      this.drawState = State.NONE;
      this.reset();
      this.releaseObjects();
    }
  };
  // 遇到轴线  必须把轴线id作为第一个
  arrangeIds() {
    const curveIds = this.curveIds;
    if (curveIds.length === 2 && axis.includes(curveIds[1])) {
      this.curveIds = [curveIds[1], curveIds[0]];
      this.vertices = [this.vertices[1], this.vertices[0]];
    }
  }
  hasCenter() {
    return (
      this.pickSnapInfo?.type === 'Circle' ||
      this.pickSnapInfo?.type === 'ArcOfCircle' ||
      this.pickSnapInfo?.type === 'Ellipse'
    );
  }
  onMouseMove = (e: EventsRes) => {
    this.setMouseWV(e, false, false);
    if (this.drawState === State.DRAWONE || this.drawState === State.DRAWTWO) {
      this.dimLinear?.update({
        labelPos: this.mouseWV,
      });
      ctx2.viewer.requestRender();
    }
  };
  callback = (status: 'focus' | 'blur') => {
    if (status === 'focus' && this.drawState <= State.DRAWTWO) {
      this.drawState = State.INPUT;
    } else if (this.drawState === State.INPUT && status === 'blur') {
      this.finishDraw();
      this.reset();
    }
  };
  addLine = () => {
    this.arrangeIds();
    if (!this.dimLinear) {
      this.dimLinear = new DimLinear({
        curveIds: this.curveIds,
        dimConstraint: AnnotationType.DimensionAnno,
        lineVertices: this.vertices,
        labelPos: this.mouseWV,
        callback: this.callback,
      });
      this.isExist = dimRender().isExistDim({
        objects: this.curveIds,
        type: 1,
      });
      this.dimLinear.addTo(this.assisGroup);
    } else {
      this.dimLinear.update({
        curveIds: this.curveIds,
        dimConstraint: AnnotationType.DistanceAnno,
        lineVertices: this.vertices,
        labelPos: this.mouseWV,
        callback: this.callback,
      });
      this.isExist = dimRender().isExistDim({
        objects: this.curveIds,
        type: 2,
      });
    }
    (this.isExist ? this.dimLinear.setDisable : this.dimLinear.unDisable)();
    this.dimLinear?.labelFoucs();
  };
  finishDraw = async () => {
    if (
      this.dimLinear?.getVal() === 0 &&
      (this.dimLinear?.curveTypes === 'Point-Point' ||
        this.dimLinear?.curveTypes === 'Line')
    ) {
      this.releaseObjects();
      return;
    }

    await addDimension(
      this.sketchId,
      {
        objects: this.curveIds,
        type: this.curveIds.length,
        value: this.dimLinear.getVal(),
        points:
          this.dimLinear.getVal() === 0
            ? [[100, 0]]
            : this.dimLinear.getPosLv(),
      },
      this.isExist,
    ).finally(() => {
      this.releaseObjects();
    });
  };

  releaseObjects() {
    this.assisGroup.clear();
    this.curveIds = [];
    this.dimLinear?.destroy();
    this.dimLinear = null;
    ctx2.viewer.requestRender();
  }
}
